Skip to content

Develop#9

Merged
Zaiidmo merged 8 commits intomasterfrom
develop
Apr 10, 2026
Merged

Develop#9
Zaiidmo merged 8 commits intomasterfrom
develop

Conversation

@a-elkhiraooui-ciscode
Copy link
Copy Markdown
Contributor

Summary

  • What does this PR change?

Why

  • Why is this change needed?

Checklist

  • Added/updated tests (if behavior changed)
  • npm run lint passes
  • npm run typecheck passes
  • npm test passes
  • npm run build passes
  • Added a changeset (npx changeset) if this affects consumers

Notes

  • Anything reviewers should pay attention to?

Zaiidmo and others added 7 commits April 1, 2026 21:01
* feat(COMPT-40): implement createQuery factory

- Add createQuery(keyFn, fetcher) returning QueryDefinition<TParams, TData>
- TData and TParams fully inferred from fetcher signature, zero manual annotation
- queryKey returns stable readonly tuple via keyFn
- useQuery shorthand hook wraps useTanstackQuery with typed params
- Export from src/index.ts
- Add @tanstack/react-query as peerDependency (>=5) and devDependency
- Add pnpm cssstyle override to fix Node.js v22 + jsdom@28 ESM compat issue
- Fix duplicate import in vitest.config.ts
- 9 tests, 100% coverage on createQuery.ts, 88.6% overall

Closes COMPT-40

* chore: sync package-lock.json with @tanstack/react-query addition

* chore: switch from pnpm to npm, sync lockfile

* chore: fix prettier formatting across all files
- usePaginatedQuery(queryDef, params, options) supports mode: 'offset' | 'cursor'
- Offset mode: page/pageSize (default 20)/nextPage/prevPage/totalPages
- Cursor mode: fetchNextPage/hasNextPage/nextCursor via useInfiniteQuery
- Both expose data as flat T[] array, isLoading, isFetching, isError, error
- Offset uses useQuery with page in queryKey; cursor uses useInfiniteQuery
- getCursor option required for cursor mode
- Typed overloads: full inference, no TanStack internals exposed
- 15 tests, 100% coverage on usePaginatedQuery.ts, 95.62% overall

Closes COMPT-41
* feat(COMPT-42): implement createMutation and typed cache helpers

- createMutation(fn) returns MutationDefinition with mutationFn and useMutation shorthand
- useMutation exposes mutate/mutateAsync/isPending/isError/error/data/reset
- invalidateQueries(client, queryDef, params?) uses queryDef key — no raw strings
- setQueryData typed updater — wrong shape is TypeScript compile error
- All exported from src/index.ts via src/query/index.ts
- 18 tests (10 mutation + 8 cache), 100% coverage on both src files, 95.94% overall

Closes COMPT-42

* chore: fix prettier formatting

* fix: suppress eslint no-unused-vars on intentionally unused mutation param
- createQuery.test.tsx: queryKey shape, queryFn call, useQuery loading/success/error/enabled/rerender
- usePaginatedQuery.test.tsx: offset page navigation, data shape, cursor fetchNextPage/hasNextPage/nextCursor
- createMutation.test.tsx: idle state, mutate, isPending, data, isError, reset, mutateAsync
- cacheHelpers.test.tsx: invalidateQueries marks stale + refetch, setQueryData direct/updater/hook reflect

All 84 tests pass, 97.35% stmt coverage (target: 85%)
- Moved all co-located tests (src/query/*.test.tsx, src/index.test.ts) into src/__tests__/
- Merged unique tests from co-located files: definition shape, stable key, TData inference,
  mode assertions, initialPage, mutationFn direct call
- Deleted: src/query/createQuery.test.tsx, cacheHelpers.test.tsx, createMutation.test.tsx,
  usePaginatedQuery.test.tsx, src/index.test.ts
- 51 tests, all passing, no test files outside src/__tests__/
- Rewrote README as an end-to-end usage guide for @ciscode/query-kit
- createQuery: key builder, fetcher, useQuery shorthand, direct key/fn access
- usePaginatedQuery: offset mode (nextPage/prevPage) and cursor mode (fetchNextPage/hasNextPage)
- createMutation + invalidateQueries full lifecycle example
- setQueryData typed updater example
- API reference table covering all exports
- Peer dep @tanstack/react-query >=5 clearly stated
- Changeset: minor bump to v0.1.0 (initial public release)
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces @ciscode/query-kit, a small typed wrapper layer around TanStack Query v5, along with accompanying tests, documentation, and CI workflow updates to support publishing and validation.

Changes:

  • Added typed query/mutation factories (createQuery, createMutation), cache helpers, and a pagination hook (usePaginatedQuery) under src/query/ and exported them via the public API.
  • Added integration tests covering the new query-kit utilities and updated documentation to describe the new package usage.
  • Updated package/workflow metadata for the new library name/versioning and strengthened CI (PR validation, release checks, publish workflow).

Reviewed changes

Copilot reviewed 19 out of 21 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
vitest.config.ts Removes duplicate import; keeps vitest setup consistent.
src/query/usePaginatedQuery.ts Adds unified pagination hook over useQuery / useInfiniteQuery.
src/query/index.ts Adds barrel exports for the new query-kit surface area.
src/query/createQuery.ts Adds typed query definition factory with useQuery shorthand.
src/query/createMutation.ts Adds typed mutation definition factory with useMutation shorthand.
src/query/cacheHelpers.ts Adds typed cache helpers for invalidation and cache writes.
src/index.ts Exposes query module as part of the library public API.
src/__tests__/usePaginatedQuery.test.tsx Adds integration tests for offset + cursor pagination behavior.
src/__tests__/createQuery.test.tsx Adds integration tests for query definition + shorthand hook.
src/__tests__/createMutation.test.tsx Adds integration tests for mutation definition + shorthand hook.
src/__tests__/cacheHelpers.test.tsx Adds integration tests for cache helper behavior.
src/__tests__/index.test.ts Adds placeholder test file.
README.md Replaces template README with package docs and examples for query-kit.
package.json Renames package, adds peer/dev deps for TanStack Query, adds repository + overrides.
package-lock.json Locks new dependencies and applies cssstyle override.
.github/workflows/release-check.yml Updates CI behavior, Node version, and SonarCloud configuration.
.github/workflows/publish.yml Updates publish validations, Node version, and uses --provenance.
.github/workflows/pr-validation.yml Adds CI workflow for PRs into develop.
.github/dependabot.yml Enables monthly Dependabot updates with grouping.
.github/CODEOWNERS Adds CODEOWNERS for repo-wide ownership.
.changeset/v0-1-0-initial-release.md Adds initial changeset for the public release.

Comment thread src/query/cacheHelpers.ts
Comment on lines +11 to +15
params?: TParams,
): Promise<void> {
const queryKey =
params !== undefined ? queryDef.queryKey(params) : queryDef.queryKey({} as TParams);
return client.invalidateQueries({ queryKey: queryKey as unknown[] });
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invalidateQueries without params currently calls queryDef.queryKey({} as TParams), which (a) can throw if keyFn expects required fields and (b) will not invalidate existing queries for paramized keys (e.g. ['posts', 1] won’t match ['posts', undefined]). Consider changing the API so the query definition provides a stable base key/prefix (or queryKey accepts params?: TParams and returns a prefix when omitted), or make params required and remove the no-params overload.

Suggested change
params?: TParams,
): Promise<void> {
const queryKey =
params !== undefined ? queryDef.queryKey(params) : queryDef.queryKey({} as TParams);
return client.invalidateQueries({ queryKey: queryKey as unknown[] });
params: TParams,
): Promise<void> {
return client.invalidateQueries({
queryKey: queryDef.queryKey(params) as unknown[],
});

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines +280 to +293
### invalidateQueries

Marks all matching queries as stale so they re-fetch. Uses the query
definition's key builder — no raw strings.

```ts
import { invalidateQueries } from '@ciscode/query-kit';

// Invalidate a specific user
await invalidateQueries(queryClient, userQuery, { id: 42 });

// Invalidate all queries matching the userQuery key prefix
await invalidateQueries(queryClient, userQuery);
```
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README claims await invalidateQueries(queryClient, userQuery); invalidates “all queries matching the userQuery key prefix”, but the current implementation builds a key from an empty object (queryKey({} as TParams)), which typically won’t match real paramized query keys. Either update the docs to reflect the actual behavior or adjust invalidateQueries to support true prefix invalidation.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to 54
- name: Validate version tag and package.json
run: |
TAG=$(git describe --exact-match --tags HEAD 2>/dev/null || echo "")
if [[ -z "$TAG" ]]; then
echo "❌ No tag found on HEAD. This push did not include a version tag."
echo "To publish, merge to master with a tag: git tag v1.0.0 && git push origin master --tags"
PKG_VERSION=$(grep '"version"' package.json | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/')
TAG="v${PKG_VERSION}"

if [[ -z "$PKG_VERSION" ]]; then
echo "❌ ERROR: Could not read version from package.json"
exit 1
fi

if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "❌ Invalid tag format: $TAG. Expected: v*.*.*"
echo "❌ ERROR: Invalid version format in package.json: '$PKG_VERSION'"
echo "Expected format: x.y.z (e.g., 1.0.0, 0.2.3)"
exit 1
fi

if ! git rev-parse "$TAG" >/dev/null 2>&1; then
echo "❌ ERROR: Tag $TAG not found!"
echo ""
echo "This typically happens when:"
echo " 1. You forgot to run 'npm version patch|minor|major' on your feature branch"
echo " 2. You didn't push the tag: git push origin <feat/your-feature> --tags"
echo " 3. The tag was created locally but never pushed to remote"
echo ""
echo "📋 Correct workflow:"
echo " 1. On feat/** or feature/**: npm version patch (or minor/major)"
echo " 2. Push branch + tag: git push origin feat/your-feature --tags"
echo " 3. PR feat/** → develop, then PR develop → master"
echo " 4. Workflow automatically triggers on master push"
echo ""
exit 1
fi
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tag validation only checks that v${package.json version} exists somewhere in the repo (git rev-parse "$TAG"), not that the tag points at the current commit being published. This can allow publishing code on master that isn’t actually tagged with the version. Consider verifying the tag is on HEAD (e.g., using git describe --exact-match --tags HEAD or checking git tag --points-at HEAD).

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/release-check.yml Outdated
-Dsonar.organization=${{ env.SONAR_ORGANIZATION }}
-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }}
-Dsonar.sources=src
-Dsonar.tests=test
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-Dsonar.tests=test points SonarCloud at a test/ directory that doesn’t exist in this repo (tests live under src/__tests__/). This will cause Sonar to misclassify tests (or ignore them) and can skew coverage/duplication metrics. Update sonar.tests to the actual test path(s) or remove it and rely on sonar.sources plus sonar.exclusions/sonar.test.inclusions as needed.

Suggested change
-Dsonar.tests=test
-Dsonar.tests=src/__tests__

Copilot uses AI. Check for mistakes.
@@ -24,15 +14,11 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 25
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow no longer sets an explicit permissions: block (unlike publish.yml and pr-validation.yml). If the repo/org default token permissions are broader than needed, this job will run with unnecessary privileges. Consider adding permissions: contents: read (and only what Sonar/checkout require) to keep least-privilege consistent across workflows.

Suggested change
timeout-minutes: 25
timeout-minutes: 25
permissions:
contents: read

Copilot uses AI. Check for mistakes.

export interface CursorPaginatedResult<TData> extends PaginatedBase<TData> {
mode: 'cursor';
fetchNextPage: () => void;
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CursorPaginatedResult.fetchNextPage is typed as () => void, but it wraps infiniteQuery.fetchNextPage() which returns a Promise. Exposing it as void prevents consumers from awaiting page loads (and makes it harder to compose with async flows/tests). Consider returning the Promise and updating the type accordingly.

Suggested change
fetchNextPage: () => void;
fetchNextPage: () => Promise<unknown>;

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +90
it('without params — calls invalidateQueries once (does not throw)', async () => {
const client = makeClient();
const spy = vi.spyOn(client, 'invalidateQueries');

await expect(invalidateQueries(client, postsQueryDef)).resolves.toBeUndefined();
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-params test only asserts that invalidateQueries doesn’t throw and that client.invalidateQueries was called once. It doesn’t verify that the intended queries are actually invalidated/refetched (which is the main value of the no-params behavior). Consider adding an assertion that queries with different params (e.g. {id:1} and {id:2}) become invalidated when calling invalidateQueries(client, postsQueryDef).

Copilot generated this review using guidance from repository custom instructions.
* feat(COMPT-44): README guide + changeset for v0.1.0

- Rewrote README as an end-to-end usage guide for @ciscode/query-kit
- createQuery: key builder, fetcher, useQuery shorthand, direct key/fn access
- usePaginatedQuery: offset mode (nextPage/prevPage) and cursor mode (fetchNextPage/hasNextPage)
- createMutation + invalidateQueries full lifecycle example
- setQueryData typed updater example
- API reference table covering all exports
- Peer dep @tanstack/react-query >=5 clearly stated
- Changeset: minor bump to v0.1.0 (initial public release)

* fix(ci): correct sonar.tests path from 'test' to 'src/__tests__'

Tests live in src/__tests__/, not test/. Also add sonar.exclusions and
sonar.test.inclusions so source files and test files are correctly separated
in SonarCloud analysis.
@sonarqubecloud
Copy link
Copy Markdown

@Zaiidmo Zaiidmo merged commit 1e489d8 into master Apr 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants